package com.shiyi.shiyiaicodefather.ai;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.shiyi.shiyiaicodefather.exception.BusinessException;
import com.shiyi.shiyiaicodefather.exception.ErrorCode;
import com.shiyi.shiyiaicodefather.model.enums.CodeGenTypeEnum;
import com.shiyi.shiyiaicodefather.service.ChatHistoryService;
import com.shiyi.shiyiaicodefather.tool.BaseTool;
import com.shiyi.shiyiaicodefather.tool.FileWriteTool;
import com.shiyi.shiyiaicodefather.tool.ToolManager;
import dev.langchain4j.community.store.memory.chat.redis.RedisChatMemoryStore;
import dev.langchain4j.data.message.ToolExecutionResultMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
@Slf4j
public class AiCodeGeneratorServiceFactory {

  @Resource
  private ChatModel chatModel;

  @Resource
  private OpenAiStreamingChatModel openAiStreamingChatModel;

  @Resource
  private StreamingChatModel reasoningStreamingChatModel;

  @Resource
  private RedisChatMemoryStore redisChatMemoryStore;

  @Resource
  private ChatHistoryService chatHistoryService;

  @Resource
  private ToolManager toolManager;


  /**
   * AI 服务实例缓存
   * 缓存策略：
   * - 最大缓存 1000 个实例
   * - 写入后 30 分钟过期
   * - 访问后 10 分钟过期
   */
  private final Cache<String, AiCodeGeneratorService> serviceCache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(Duration.ofMinutes(30))
    .expireAfterAccess(Duration.ofMinutes(10))
    .removalListener((key, value, cause) -> {
      log.debug("AI 服务实例被移除，appId: {}, 原因: {}", key, cause);
    })
    .build();

  /**
   * 根据 appId 获取服务（带缓存）兼容历史逻辑
   */
  public AiCodeGeneratorService getAiCodeGeneratorService(long appId) {
    return getAiCodeGeneratorService(appId,CodeGenTypeEnum.HTML);
  }

  /**
   * 根据 appId 获取服务（带缓存）
   */
  public AiCodeGeneratorService getAiCodeGeneratorService(long appId, CodeGenTypeEnum codeGenTypeEnum) {
    String cacheKey = buildCacheKey(appId, codeGenTypeEnum);
    return serviceCache.get(cacheKey, key -> createAiCodeGeneratorService(appId, codeGenTypeEnum));
  }


  public AiCodeGeneratorService createAiCodeGeneratorService(long appId, CodeGenTypeEnum codeGenTypeEnum) {
    log.info("创建 AI 服务实例，appId: {}", appId);
    //为每个appId创建独立的对话记忆
    MessageWindowChatMemory messageWindowChatMemory = MessageWindowChatMemory.builder()
      .id(appId)
      .chatMemoryStore(redisChatMemoryStore)
      .maxMessages(20)
      .build();
    //从数据库加载历史对话到记忆中
    chatHistoryService.loadChatHistoryToMemory(appId, messageWindowChatMemory,50);

    return switch (codeGenTypeEnum) {
      case VUE_PROJECT ->
        AiServices.builder(AiCodeGeneratorService.class)
        .streamingChatModel(reasoningStreamingChatModel)
        .chatMemoryProvider(memoryId -> messageWindowChatMemory)
          .tools(toolManager.getAllTools())
          .hallucinatedToolNameStrategy(toolExecutionRequest ->
            ToolExecutionResultMessage.from(toolExecutionRequest,  "Error: there is no tool called " + toolExecutionRequest.name()))
        .build();
      case HTML,MULTI_FILE ->
       AiServices.builder(AiCodeGeneratorService.class)
        .chatModel(chatModel)
        .streamingChatModel(openAiStreamingChatModel)
        .chatMemory(messageWindowChatMemory)
        .build();
      default -> throw new BusinessException(ErrorCode.SYSTEM_ERROR,"不支持的代码生成类型: " + codeGenTypeEnum);
    };

  }

  @Bean
  public AiCodeGeneratorService aiCodeGeneratorService() {
    return getAiCodeGeneratorService(0);
  }

  private String buildCacheKey(long appId,CodeGenTypeEnum codeGenTypeEnum) {
    return appId + "_" + codeGenTypeEnum.getValue();
  }
}
